home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / shllutil.lha / shellutils-1.8 / src / expr.c < prev    next >
C/C++ Source or Header  |  1992-07-24  |  11KB  |  673 lines

  1. /* expr -- evaluate expressions.
  2.    Copyright (C) 1986, 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Author: Mike Parker.
  19.  
  20.    This program evaluates expressions.  Each token (operator, operand,
  21.    parenthesis) of the expression must be a seperate argument.  The
  22.    parser used is a reasonably general one, though any incarnation of
  23.    it is language-specific.  It is especially nice for expressions.
  24.  
  25.    No parse tree is needed; a new node is evaluated immediately.
  26.    One function can handle multiple operators all of equal precedence,
  27.    provided they all associate ((x op x) op x).
  28.  
  29.    Define EVAL_TRACE to print an evaluation trace.  */
  30.  
  31. #include <stdio.h>
  32. #include <ctype.h>
  33. #include <sys/types.h>
  34. #include <regex.h>
  35. #include "system.h"
  36.  
  37. #if !__STDC__
  38. #define const
  39. #endif
  40.  
  41. #define NEW(type) ((type *) xmalloc (sizeof (type)))
  42. #define OLD(x) free ((char *) x)
  43.  
  44. /* The kinds of value we can have.  */
  45. enum valtype
  46. {
  47.   integer,
  48.   string
  49. };
  50. typedef enum valtype TYPE;
  51.  
  52. /* A value is.... */
  53. struct valinfo
  54. {
  55.   TYPE type;            /* Which kind. */
  56.   union
  57.   {                /* The value itself. */
  58.     int i;
  59.     char *s;
  60.   } u;
  61. };
  62. typedef struct valinfo VALUE;
  63.  
  64. /* The arguments given to the program, minus the program name.  */
  65. char **args;
  66.  
  67. /* The name this program was run with. */
  68. char *program_name;
  69.  
  70. VALUE *docolon ();
  71. VALUE *eval ();
  72. VALUE *int_value ();
  73. VALUE *str_value ();
  74. char *xstrdup ();
  75. char *strstr ();
  76. char *xmalloc ();
  77. int isstring ();
  78. int nextarg ();
  79. int nomoreargs ();
  80. int null ();
  81. int toarith ();
  82. void error ();
  83. void freev ();
  84. void printv ();
  85. void tostring ();
  86. void trace ();
  87.  
  88. void
  89. main (argc, argv)
  90.      int argc;
  91.      char **argv;
  92. {
  93.   VALUE *v;
  94.  
  95.   program_name = argv[0];
  96.  
  97.   if (argc == 1)
  98.     {
  99.       fprintf (stderr, "Usage: %s expression...\n", argv[0]);
  100.       exit (1);
  101.     }
  102.   args = argv + 1;
  103.  
  104.   v = eval ();
  105.   if (!nomoreargs ())
  106.     error (2, 0, "syntax error");
  107.   printv (v);
  108.  
  109.   exit (null (v));
  110. }
  111.  
  112. /* Return a VALUE for I.  */
  113.  
  114. VALUE *
  115. int_value (i)
  116.      int i;
  117. {
  118.   VALUE *v;
  119.  
  120.   v = NEW (VALUE);
  121.   v->type = integer;
  122.   v->u.i = i;
  123.   return v;
  124. }
  125.  
  126. /* Return a VALUE for S.  */
  127.  
  128. VALUE *
  129. str_value (s)
  130.      char *s;
  131. {
  132.   VALUE *v;
  133.  
  134.   v = NEW (VALUE);
  135.   v->type = string;
  136.   v->u.s = xstrdup (s);
  137.   return v;
  138. }
  139.  
  140. /* Free VALUE V, including structure components.  */
  141.  
  142. void
  143. freev (v)
  144.      VALUE *v;
  145. {
  146.   if (v->type == string)
  147.     free (v->u.s);
  148.   OLD (v);
  149. }
  150.  
  151. /* Print VALUE V.  */
  152.  
  153. void
  154. printv (v)
  155.      VALUE *v;
  156. {
  157.   switch (v->type)
  158.     {
  159.     case integer:
  160.       printf ("%d\n", v->u.i);
  161.       break;
  162.     case string:
  163.       printf ("%s\n", v->u.s);
  164.       break;
  165.     }
  166. }
  167.  
  168. /* Return nonzero if V is a null-string or zero-number.  */
  169.  
  170. int
  171. null (v)
  172.      VALUE *v;
  173. {
  174.   switch (v->type)
  175.     {
  176.     case integer:
  177.       return v->u.i == 0;
  178.     case string:
  179.       return v->u.s[0] == '\0';
  180.     }
  181. }
  182.  
  183. /* Return nonzero if V is a string value.  */
  184.  
  185. int
  186. isstring (v)
  187.      VALUE *v;
  188. {
  189.   return v->type == string;
  190. }
  191.  
  192. /* Coerce V to a string value (can't fail).  */
  193.  
  194. void
  195. tostring (v)
  196.      VALUE *v;
  197. {
  198.   char *temp;
  199.  
  200.   switch (v->type)
  201.     {
  202.     case integer:
  203.       temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
  204.       sprintf (temp, "%d", v->u.i);
  205.       v->u.s = temp;
  206.       v->type = string;
  207.       break;
  208.     case string:
  209.       break;
  210.     }
  211. }
  212.  
  213. /* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
  214.  
  215. int
  216. toarith (v)
  217.      VALUE *v;
  218. {
  219.   int i;
  220.   int neg;
  221.   char *cp;
  222.  
  223.   switch (v->type)
  224.     {
  225.     case integer:
  226.       return 1;
  227.     case string:
  228.       i = 0;
  229.       cp = v->u.s;
  230.       neg = (*cp == '-');
  231.       if (neg)
  232.     cp++;
  233.       for (; *cp; cp++)
  234.     {
  235.       if (isdigit (*cp))
  236.         i = i * 10 + *cp - '0';
  237.       else
  238.         return 0;
  239.     }
  240.       free (v->u.s);
  241.       v->u.i = i * (neg ? -1 : 1);
  242.       v->type = integer;
  243.       return 1;
  244.     }
  245. }
  246.  
  247. /* Return nonzero if the next token matches STR exactly.
  248.    STR must not be NULL.  */
  249.  
  250. int
  251. nextarg (str)
  252.      char *str;
  253. {
  254.   if (*args == NULL)
  255.     return 0;
  256.   return strcmp (*args, str) == 0;
  257. }
  258.  
  259. /* Return nonzero if there no more tokens.  */
  260.  
  261. int
  262. nomoreargs ()
  263. {
  264.   return *args == 0;
  265. }
  266.  
  267. /* The comparison operator handling functions.  */
  268.  
  269. #define cmpf(name, rel)                \
  270. int name (l, r) VALUE *l; VALUE *r;        \
  271. {                        \
  272.   if (isstring (l) || isstring (r))        \
  273.     {                        \
  274.        tostring (l);                \
  275.        tostring (r);                \
  276.        return strcmp (l->u.s, r->u.s) rel 0;    \
  277.     }                        \
  278.  else                        \
  279.    return l->u.i rel r->u.i;            \
  280. }
  281.  
  282. cmpf (less_than, <)
  283. cmpf (less_equal, <=)
  284. cmpf (equal, ==)
  285. cmpf (not_equal, !=)
  286. cmpf (greater_equal, >=)
  287. cmpf (greater_than, >)
  288.  
  289. #undef cmpf
  290.  
  291. /* The arithmetic operator handling functions.  */
  292.  
  293. #define arithf(name, op)            \
  294. int name (l, r) VALUE *l; VALUE *r;        \
  295. {                        \
  296.   if (!toarith (l) || !toarith (r))        \
  297.     error (2, 0, "non-numeric argument");    \
  298.   return l->u.i op r->u.i;            \
  299. }
  300.  
  301. arithf (plus, +)
  302. arithf (minus, -)
  303. arithf (multiply, *)
  304. arithf (divide, /)
  305. arithf (mod, %)
  306.  
  307. #undef arithf
  308.  
  309. #ifdef EVAL_TRACE
  310. /* Print evaluation trace and args remaining.  */
  311.  
  312. void
  313. trace (fxn)
  314.      char *fxn;
  315. {
  316.   char **a;
  317.  
  318.   printf ("%s:", fxn);
  319.   for (a = args; *a; a++)
  320.     printf (" %s", *a);
  321.   putchar ('\n');
  322. }
  323. #endif
  324.  
  325. /* Do the : operator.
  326.    SV is the VALUE for the lhs (the string),
  327.    PV is the VALUE for the rhs (the pattern).  */
  328.  
  329. VALUE *
  330. docolon (sv, pv)
  331.      VALUE *sv;
  332.      VALUE *pv;
  333. {
  334.   VALUE *v;
  335.   const char *errmsg;
  336.   struct re_pattern_buffer re_buffer;
  337.   struct re_registers re_regs;
  338.   int len;
  339.  
  340.   tostring (sv);
  341.   tostring (pv);
  342.  
  343.   len = strlen (pv->u.s);
  344.   re_buffer.allocated = 2 * len;
  345.   re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
  346.   re_buffer.translate = 0;
  347.   errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
  348.   if (errmsg)
  349.     error (2, 0, "%s", errmsg);
  350.  
  351.   len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
  352.   if (len >= 0)
  353.     {
  354.       /* Were \(...\) used? */
  355.       if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
  356.     {
  357.       sv->u.s[re_regs.end[1]] = '\0';
  358.       v = str_value (sv->u.s + re_regs.start[1]);
  359.     }
  360.       else
  361.     v = int_value (len);
  362.     }
  363.   else
  364.     {
  365.       /* Match failed -- return the right kind of null.  */
  366.       if (strstr (pv->u.s, "\\("))
  367.     v = str_value ("");
  368.       else
  369.     v = int_value (0);
  370.     }
  371.   free (re_buffer.buffer);
  372.   return v;
  373. }
  374.  
  375. /* Handle bare operands and ( expr ) syntax.  */
  376.  
  377. VALUE *
  378. eval7 ()
  379. {
  380.   VALUE *v;
  381.  
  382. #ifdef EVAL_TRACE
  383.   trace ("eval7");
  384. #endif
  385.   if (nomoreargs ())
  386.     error (2, 0, "syntax error");
  387.   else if (nextarg ("("))
  388.     {
  389.       args++;
  390.       v = eval ();
  391.       if (!nextarg (")"))
  392.     error (2, 0, "syntax error");
  393.       args++;
  394.       return v;
  395.     }
  396.   else if (nextarg (")"))
  397.     error (2, 0, "syntax error");
  398.   else
  399.     return str_value (*args++);
  400. }
  401.  
  402. /* Handle match, substr, index, and length keywords.  */
  403.  
  404. VALUE *
  405. eval6 ()
  406. {
  407.   VALUE *l;
  408.   VALUE *r;
  409.   VALUE *v;
  410.   VALUE *i1;
  411.   VALUE *i2;
  412.  
  413. #ifdef EVAL_TRACE
  414.   trace ("eval6");
  415. #endif
  416.   if (nextarg ("length"))
  417.     {
  418.       args++;
  419.       r = eval6 ();
  420.       tostring (r);
  421.       v = int_value (strlen (r->u.s));
  422.       freev (r);
  423.       return v;
  424.     }
  425.   else if (nextarg ("match"))
  426.     {
  427.       args++;
  428.       l = eval6 ();
  429.       r = eval6 ();
  430.       v = docolon (l, r);
  431.       freev (l);
  432.       freev (r);
  433.       return v;
  434.     }
  435.   else if (nextarg ("index"))
  436.     {
  437.       args++;
  438.       l = eval6 ();
  439.       r = eval6 ();
  440.       tostring (l);
  441.       tostring (r);
  442.       v = int_value (strcspn (l->u.s, r->u.s) + 1);
  443.       if (v->u.i == strlen (l->u.s) + 1)
  444.     v->u.i = 0;
  445.       freev (l);
  446.       freev (r);
  447.       return v;
  448.     }
  449.   else if (nextarg ("substr"))
  450.     {
  451.       args++;
  452.       l = eval6 ();
  453.       i1 = eval6 ();
  454.       i2 = eval6 ();
  455.       tostring (l);
  456.       if (!toarith (i1) || !toarith (i2)
  457.       || i1->u.i > strlen (l->u.s)
  458.       || i1->u.i <= 0 || i2->u.i <= 0)
  459.     v = str_value ("");
  460.       else
  461.     {
  462.       v = NEW (VALUE);
  463.       v->type = string;
  464.       v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
  465.                 l->u.s + i1->u.i - 1, i2->u.i);
  466.     }
  467.       freev (l);
  468.       freev (i1);
  469.       freev (i2);
  470.       return v;
  471.     }
  472.   else
  473.     return eval7 ();
  474. }
  475.  
  476. /* Handle : operator (pattern matching).
  477.    Calls docolon to do the real work.  */
  478.  
  479. VALUE *
  480. eval5 ()
  481. {
  482.   VALUE *l;
  483.   VALUE *r;
  484.   VALUE *v;
  485.  
  486. #ifdef EVAL_TRACE
  487.   trace ("eval5");
  488. #endif
  489.   l = eval6 ();
  490.   while (1)
  491.     {
  492.       if (nextarg (":"))
  493.     {
  494.       args++;
  495.       r = eval6 ();
  496.       v = docolon (l, r);
  497.       freev (l);
  498.       freev (r);
  499.       l = v;
  500.     }
  501.       else
  502.     return l;
  503.     }
  504. }
  505.  
  506. /* Handle *, /, % operators.  */
  507.  
  508. VALUE *
  509. eval4 ()
  510. {
  511.   VALUE *l;
  512.   VALUE *r;
  513.   int (*fxn) ();
  514.   int val;
  515.  
  516. #ifdef EVAL_TRACE
  517.   trace ("eval4");
  518. #endif
  519.   l = eval5 ();
  520.   while (1)
  521.     {
  522.       if (nextarg ("*"))
  523.     fxn = multiply;
  524.       else if (nextarg ("/"))
  525.     fxn = divide;
  526.       else if (nextarg ("%"))
  527.     fxn = mod;
  528.       else
  529.     return l;
  530.       args++;
  531.       r = eval5 ();
  532.       val = (*fxn) (l, r);
  533.       freev (l);
  534.       freev (r);
  535.       l = int_value (val);
  536.     }
  537. }
  538.  
  539. /* Handle +, - operators.  */
  540.  
  541. VALUE *
  542. eval3 ()
  543. {
  544.   VALUE *l;
  545.   VALUE *r;
  546.   int (*fxn) ();
  547.   int val;
  548.  
  549. #ifdef EVAL_TRACE
  550.   trace ("eval3");
  551. #endif
  552.   l = eval4 ();
  553.   while (1)
  554.     {
  555.       if (nextarg ("+"))
  556.     fxn = plus;
  557.       else if (nextarg ("-"))
  558.     fxn = minus;
  559.       else
  560.     return l;
  561.       args++;
  562.       r = eval4 ();
  563.       val = (*fxn) (l, r);
  564.       freev (l);
  565.       freev (r);
  566.       l = int_value (val);
  567.     }
  568. }
  569.  
  570. /* Handle comparisons.  */
  571.  
  572. VALUE *
  573. eval2 ()
  574. {
  575.   VALUE *l;
  576.   VALUE *r;
  577.   int (*fxn) ();
  578.   int val;
  579.  
  580. #ifdef EVAL_TRACE
  581.   trace ("eval2");
  582. #endif
  583.   l = eval3 ();
  584.   while (1)
  585.     {
  586.       if (nextarg ("<"))
  587.     fxn = less_than;
  588.       else if (nextarg ("<="))
  589.     fxn = less_equal;
  590.       else if (nextarg ("=") || nextarg ("=="))
  591.     fxn = equal;
  592.       else if (nextarg ("!="))
  593.     fxn = not_equal;
  594.       else if (nextarg (">="))
  595.     fxn = greater_equal;
  596.       else if (nextarg (">"))
  597.     fxn = greater_than;
  598.       else
  599.     return l;
  600.       args++;
  601.       r = eval3 ();
  602.       toarith (l);
  603.       toarith (r);
  604.       val = (*fxn) (l, r);
  605.       freev (l);
  606.       freev (r);
  607.       l = int_value (val);
  608.     }
  609. }
  610.  
  611. /* Handle &.  */
  612.  
  613. VALUE *
  614. eval1 ()
  615. {
  616.   VALUE *l;
  617.   VALUE *r;
  618.  
  619. #ifdef EVAL_TRACE
  620.   trace ("eval1");
  621. #endif
  622.   l = eval2 ();
  623.   while (1)
  624.     {
  625.       if (nextarg ("&"))
  626.     {
  627.       args++;
  628.       r = eval2 ();
  629.       if (null (l) || null (r))
  630.         {
  631.           freev (l);
  632.           freev (r);
  633.           l = int_value (0);
  634.         }
  635.       else
  636.         freev (r);
  637.     }
  638.       else
  639.     return l;
  640.     }
  641. }
  642.  
  643. /* Handle |.  */
  644.  
  645. VALUE *
  646. eval ()
  647. {
  648.   VALUE *l;
  649.   VALUE *r;
  650.  
  651. #ifdef EVAL_TRACE
  652.   trace ("eval");
  653. #endif
  654.   l = eval1 ();
  655.   while (1)
  656.     {
  657.       if (nextarg ("|"))
  658.     {
  659.       args++;
  660.       r = eval1 ();
  661.       if (null (l))
  662.         {
  663.           freev (l);
  664.           l = r;
  665.         }
  666.       else
  667.         freev (r);
  668.     }
  669.       else
  670.     return l;
  671.     }
  672. }
  673.